
package andre.grids.network;

import andre.grids.db.*;
import andre.grids.db.dataclasses.*;
import andre.grids.filesystem.common.*;
import andre.grids.filesystem.server.configuration.ConfigurationManager;
import andre.grids.util.QueueHashTable;
import java.util.*;
import java.rmi.*;

/**
 *
 * @author andre
 */
public class FileServerTable {
    
    private QueueHashTable<String, PeerObjects> fileServers;
    
    public FileServerTable() {
        fileServers = new QueueHashTable<String, PeerObjects>(200);
        loadPeersFromDb();
        updateFromList(ConfigurationManager.getFileServerList());        
    }
    
    public void addServer(String hostName) {
        if (fileServers.containsKey(hostName))
        {
            try
            {
                PeerObjects objs = fileServers.get(hostName);
                objs.release();
                objs = new PeerObjects(hostName,true); // cria somente os objetos de arquivo.
                fileServers.remove(hostName);                
                fileServers.put(hostName, objs);
            }
            catch(Exception e)
            {
                andre.grids.util.log.Log.logException(e, this);
                return;
            }
        }
        else // nunca foi adicionado à tabela, portanto deve verificar se já existe no banco
        {
            DbPeer peer = (new DbPeerQueries()).getPeerByName(hostName);
            
            if (peer == null) { // nunca foi adicionado ao banco
                peer = new DbPeer();
                peer.setPeerName(hostName);
                peer.setDirectoryMaster(false);
                peer.setFileReplica(true);
                Database db = Database.getGridFsDb();
                db.storeObjectTree(peer);
            }
            
            PeerObjects objs = null;
            
            try
            {
                objs = new PeerObjects(peer.getPeerName(),true);            
            }
            catch(Exception e)
            {
                andre.grids.util.log.Log.logException(e, peer);
                return;
            }
            fileServers.put(peer.getPeerName(), objs);
        }
    }
    
    public PeerObjects getObjectsFor(String hostName) throws RemoteException
    {
        if (!fileServers.containsKey(hostName))
            return null;
        PeerObjects objs = fileServers.get(hostName);
        if (objs == null)
        {
            objs = new PeerObjects(hostName,true);
            fileServers.put(hostName, objs);
            return objs;
        }
        return fileServers.get(hostName);
    }    
    
    public Enumeration<PeerObjects> getAllObjects()
    {
        Enumeration<String> hosts = fileServers.keys();
        
        // este trecho do codigo inicializa todos os 
        // objetos armazenados na tabela
        while(hosts.hasMoreElements()) {
            try {
                String host;
                host = hosts.nextElement();
                getObjectsFor(host);
            } catch(Exception e) {
                andre.grids.util.log.Log.logException(e, this);
            }
        }
        
        return fileServers.elements();
    }    
    
    private void loadPeersFromDb() {
        DbPeerQueries query = new DbPeerQueries();        
        Vector<DbPeer> servers =query.getFileServers();
        for(DbPeer p: servers)
            this.addServer(p.getPeerName());
    }
    
    private void updateFromList(String [] serversList) {
        Database db = Database.getGridFsDb();
        DbPeerQueries query = new DbPeerQueries();
        Vector<DbPeer> list = query.getFileServers();
        String [] alreadyInDb = new String[list.size()];
        for(int i = 0; i < alreadyInDb.length; i++)
            alreadyInDb[i] = list.get(i).getPeerName();
        java.util.Arrays.sort(alreadyInDb);
        for(int i = 0; i < serversList.length; i++)
        {
            if (java.util.Arrays.binarySearch(alreadyInDb, serversList[i]) == -1)
            {
                DbPeer peer;
                peer = new DbPeer();
                peer.setDirectoryMaster(false);
                peer.setFileReplica(true);
                peer.setPeerName(serversList[i]);
                db.storeObjectTree(peer);
            }
        }
        loadPeersFromDb();        
    }
    
    public PeerObjects[] getFreeObjects() {
        List<PeerObjects> lista = fileServers.get(3);
        PeerObjects[] array = new PeerObjects[lista.size()];
        lista.toArray(array);
        return array;
    }
    
    private static FileServerTable instance;
    public static FileServerTable getInstance() {
        if (instance == null)
            instance = new FileServerTable();
        return instance;
    }
}
